killall为什么有时候会找不到进程? 您所在的位置:网站首页 roslaunch 未找到命令 killall为什么有时候会找不到进程?

killall为什么有时候会找不到进程?

2023-07-18 01:34| 来源: 网络整理| 查看: 265

 

前言

在Linux下有很多命令用于杀死进程,它们可以用于不同的场景,例如通过进程名杀死进程,通过pid杀死进程。这些方法我不准备一一列举,本文想说明的一个问题是,为什么明明通过ps找到了进程,但是通过killall却说找不到呢?如果你没有遇到过这样的问题?那你更要注意了!

killall简介

与kill不同的是,killall可以根据进程名来杀死进程,不像kill,可能先需要使用ps(可以参考《ps命令实例详解》)找到进程id,然后发送信号,就像下面这样:

$ ps -ef|grep hello root      15530  6335  0 14:55 pts/4    00:00:00 ./hello $ kill -9 15530

这样进程就被我们杀死了,我们可以直接使用killall:

$ killall hello

是不是觉得方便多了?

而且由于killall是根据名称杀死进程,因此如果当前运行着大量的hello程序,那么可以一次性杀死所有hello程序。

除此之外,它还有很多参数,例如忽略大小写,根据模式匹配进程名,杀死某个时间的进程等等,这里就不详解介绍了,有兴趣的可以查看man killall手册。

今天这里想要说明的是一种killall失效的情况。

killall失效了?

我写了一个自己的hello程序,然后尝试使用killall杀死正在运行的hello程序。

$  killall hello hello: no process found

什么?竟然说找不到?一个ps丢过来:

$ ps -ef|grep hello root      15765  6335  0 15:05 pts/4    00:00:00 ./hello

所以killall你到底行不行?

为何

为了找出killall失效的原因,我们必须知道它到底是如何通过进程名找到进程的。 这个时候就需要祭出我们的神器strace了,看看killall杀死一个普通进程到底做了哪些事情:

$ strace killall hello open("/proc/100/cmdline", O_RDONLY)     = 3 fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 read(3, "", 1024)                       = 0 close(3)                                = 0 open("/proc/104/stat", O_RDONLY)        = 3 fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 read(3, "104 (ipv6_addrconf) I 2 0 0 0 -1"..., 1024) = 161 close(3)                                = 0 open("/proc/113/stat", O_RDONLY)        = 3 fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 read(3, "113 (kstrp) I 2 0 0 0 -1 6923888"..., 1024) = 153 close(3)                                = 0 open("/proc/137/stat", O_RDONLY)        = 3 fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 read(3, "137 (charger_manager) I 2 0 0 0 "..., 1024) = 163 close(3)                                = 0 open("/proc/137/cmdline", O_RDONLY)     = 3 fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 read(3, "", 1024)                       = 0

打印结果很多,我只提取了部分,可以看到的是,killall会去proc文件系统(proc文件系统可以参考《Linux中不可错过的信息宝库》)下查找各个进程id下的stat文件和cmdline,stat文件是怎样的呢?我们随便找一个看看:

$ cat /proc/16131/stat  16131 (hello) S 6335 16131 6335 34820 16131 1077936128 70 0 0 0 0 0 0 0 20 0 1 0 2465163 4321280 194 18446744073709551615 4194304 4196092 140734969955328 0 0 0 0 0 0 1 0 0 17 0 0 0 0 0 0 6295056 6295608 19099648 140734969962804 140734969962812 140734969962812 140734969966576 0

我们不要被这么多内容吓到了,可以明显看到的是,里面有hello啊。至此我们可以猜测,killall命令会去读取进程在proc文件系统中的stat文件里的名字。那么如果这么名字和你要杀死的进程对不上不就找不到了吗?

至此,想必你已经明白前面问题的原因了。

如何给自挖坑

那么怎样修改stat中显示的名字呢?我们可以使用prcl函数,话不多少,直接看示例代码:

//来源:公众号【编程珠玑】 //作者:守望先生 #include #include #include int main(void) {     prctl(PR_SET_NAME,"bianchengzhuji");      sleep(100);//防止进程立即退出,便于观察     return 0; }

这个时候再编译运行程序查看stat和status中的名字:

$ gcc -o hello hello.c $ cat /proc/pid/stat  #这里的pid换成示例的进程id 16441 (bianchengzhuji) S 6335 16441 6335 34820 16441 1077936128 69 0 0 0 0 0 0 0 20 0 1 0 2535513 4321280 156 18446744073709551615 4194304 4196188 140724949606512 0 0 0 0 0 0 1 0 0 17 3 0 0 0 0 0 6295056 6295616 31719424 140724949614900 140724949614908 140724949614908 140724949618672 0 $ more /proc/pid/status Name:    bianchengzhuji Umask:    0002 State:    S (sleeping) Tgid:    16441 Ngid:    0 Pid:    16441 PPid:    6335

是不是发现名字变了呢?虽然进程名还是hello,但是killall已经找不到它了,不过:

$ killall bianchengzhuji

还是可以的。

为什么会出现这种情况呢? 想象一下,你们公司内部不想重复造轮子,搞了一套开发框架,main函数在框架里写好了,通过库的形式给你们使用,可能名字早就定好了。或者是多线程程序,它的名字是main。

但是,这里需要特别注意的是,如果名字超过了15个字符,在stat和status文件中看到的将会看到被截断的名字。

玩点刺激的

既然看到这里了,不如再玩点刺激的。

看看下面的代码:

//来源:公众号【编程珠玑】 #include #include #include int main(int argc,char *argv[]) {     strncpy(argv[0],"bianchengzhuji",sizeof("bianchengzhuji"));     sleep(100);     return 0; }

是不是发现和前面例子的main函数不一样?参考这里(《C语言的main到底该怎么写》) 这个时候你去编译运行:

$ gcc -o hello hello.c $ ./hello

然后尝试使用ps去查找进程:

$ ps -ef|grep hello root      17831 17818  0 16:09 pts/26   00:00:00 grep --color=auto hello

然后你就会惊喜的发现找不到hello进程。 但是使用:

$ ps -ef|grep shouwangxiansheng root      17938  6335  0 16:12 pts/4    00:00:00 shouwangxiansheng root      17954 17924  0 16:12 pts/27   00:00:00 grep --color=auto shouwangxiansheng hyb@ub

就可以找到。

这种情况下直接改变了程序的命令名,因此ps之类的找不到。 这个时候看命令名是什么呢?

$ cat /proc/17938/cmdline shouwangxiansheng

不过这个时候killall还是可以找到它!也就是你可以使用killall hello杀死它。

总结

如果你发现你的程序无法通过killall 进程名的方式杀死的话,不妨看看proc文件系统中这个进程的stat文件或者status文件中的名。

推荐阅读:

每天都在用printf,你知道变长参数是怎么实现的吗

几个命令了解ELF文件的”秘密“

 

首发:公众号【编程珠玑】

作者:守望先生

ID:shouwangxiansheng

关注公众号【编程珠玑】,获取更多Linux/C/C++/算法/计算机基础/工具等原创技术文章。后台免费获取经典电子书和视频资源



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有